Further learning: https://autogis-site.readthedocs.io/en/latest/index.html
Norway shapefile: https://kartkatalog.geonorge.no/metadata/administrative-enheter-fylker/6093c8a8-fa80-11e6-bc64-92361f002671
GeoPandas, as the name suggests, extends the popular data science library pandas by adding support for geospatial data. If you are not familiar with pandas, we recommend taking a quick look at its Getting started documentation before proceeding.
The core data structure in GeoPandas is the geopandas.GeoDataFrame, a subclass of pandas.DataFrame, that can store geometry columns and perform spatial operations. The geopandas.GeoSeries, a subclass of pandas.Series, handles the geometries. Therefore, your GeoDataFrame is a combination of pandas.Series, with traditional data (numerical, boolean, text etc.), and geopandas.GeoSeries, with geometries (points, polygons etc.). You can have as many columns with geometries as you wish; there’s no limit typical for desktop GIS software.
Each GeoSeries can contain any geometry type (you can even mix them within a single array) and has a GeoSeries.crs attribute, which stores information about the projection (CRS stands for Coordinate Reference System). Therefore, each GeoSeries in a GeoDataFrame can be in a different projection, allowing you to have, for example, multiple versions (different projections) of the same geometry.
Only one GeoSeries in a GeoDataFrame is considered the active geometry, which means that all geometric operations applied to a GeoDataFrame operate on this active column.
import geopandas as gpd
Assuming you have a file containing both data and geometry (e.g. GeoPackage, GeoJSON, Shapefile), you can read it using geopandas.read_file(), which automatically detects the filetype and creates a GeoDataFrame. This tutorial uses the "nybb" dataset, a map of New York boroughs, which is part of the GeoPandas installation. Therefore, we use geopandas.datasets.get_path() to retrieve the path to the dataset.
gdf = gpd.read_file('data/trafikkregistreringsstasjoner_e6.geojson')
gdf
| Registreringsnivå | Antall kjørefelt | Status | Stasjonsnavn | Målestasjonsnummer | id | metadata | vegsystem | strekning | kortform | veglenkesekvensid | relativPosisjon | veglenkeType | detaljnivå | startdato | kommune | fylke | sluttdato | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Kontinuerlig (Nivå 1) | 2.0 | Operativ | BIRI SØR | 500513 | 370075065 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1002317285, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 34, 'de... | EV6 S34D1 m1024 | 1060614 | 0.161844 | HOVED | Vegtrase | 2021-11-08 | 3407 | 34 | None | POINT Z (264149.468 6763845.476 126.247) |
| 1 | Kontinuerlig (Nivå 1) | 6.0 | Operativ | SKULLERUD | 300039 | 370075067 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1006190638, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 15, 'de... | EV6 S15D1 m5271 | 625212 | 0.546885 | HOVED | Vegtrase | 2021-11-29 | 301 | 3 | None | POINT Z (266588.338 6643481.572 96.660) |
| 2 | Kontinuerlig (Nivå 1) | 4.0 | Operativ | LEIRELVA BRU | 200211 | 370075069 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1002316638, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 20, 'de... | EV6 S20D1 m5058 | 444220 | 0.305518 | HOVED | Vegtrase | 2021-11-29 | 3030 | 30 | None | POINT Z (282658.009 6661281.184 122.767) |
| 3 | Kontinuerlig (Nivå 1) | 6.0 | Midlertidig ute av drift | E6 V/KARIHAUGEN | 300349 | 370075137 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1002316825, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 17, 'de... | EV6 S17D1 m5998 | 625215 | 0.798544 | HOVED | Vegtrase | 2021-11-29 | 301 | 3 | None | POINT Z (272890.578 6651710.794 177.096) |
| 4 | Kontinuerlig (Nivå 1) | 2.0 | Operativ | Nordkjosbotn sør | 1900211 | 370075139 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1006190674, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 179, 'd... | EV6 S179D1 m12163 | 1126289 | 0.567433 | HOVED | Vegtrase og kjørebane | 2021-12-01 | 5422 | 54 | None | POINT Z (679838.689 7684871.107 3.039) |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 242 | Kontinuerlig (Nivå 1) | NaN | Operativ | LANGFJORDBOTN X882 | 2000009 | 1014031313 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1006190681, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 199, 'd... | EV6 S199D1 m1854 | 930225 | 0.217697 | HOVED | Vegtrase og kjørebane | 2021-12-01 | 5403 | 54 | None | POINT Z (775891.977 7786772.901 39.026) |
| 243 | Kontinuerlig (Nivå 1) | NaN | Operativ | Bjørkheim X | 3000367 | 1014047386 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1006190636, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 243, 'd... | EV6 S243D1 m7212 | 2604164 | 0.225644 | HOVED | Vegtrase og kjørebane | 2021-09-28 | 5444 | 54 | None | POINT Z (1076207.450 7802256.597 60.649) |
| 244 | Kontinuerlig (Nivå 1) | NaN | Operativ | E6 Alnabru Nordgående Morpunkt | 300146 | 1014062385 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1006190639, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 16, 'de... | EV6 S16D1 m6497 | 625213 | 0.896827 | HOVED | Vegtrase og kjørebane | 2021-11-29 | 301 | 3 | None | POINT Z (266860.793 6650152.076 95.680) |
| 245 | Kontinuerlig (Nivå 1) | NaN | Operativ | Grong | 1700019 | 1014067467 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1002317857, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 97, 'de... | EV6 S97D1 m9121 | 578609 | 0.909206 | HOVED | Vegtrase | 2021-11-23 | 5045 | 50 | None | POINT Z (370173.334 7151626.029 25.234) |
| 246 | Kontinuerlig (Nivå 1) | NaN | Operativ | E6 SYNSTERUD | 3000501 | 1014096768 | {'type': {'id': 482, 'navn': 'Trafikkregistrer... | {'id': 1002317896, 'versjon': 1, 'vegkategori'... | {'id': -1, 'versjon': -1, 'strekning': 29, 'de... | EV6 S29D1 m10832 | 2823418 | 0.031060 | HOVED | Vegtrase | 2021-10-14 | 3413 | 34 | None | POINT Z (295209.700 6736968.012 194.489) |
247 rows × 19 columns
To write a GeoDataFrame back to file use GeoDataFrame.to_file(). The default file format is Shapefile, but you can specify your own with the driver keyword.
gdf.to_file("my_file.geojson", driver="GeoJSON")
norge = gpd.read_file('./data/norge.geojson')
norge
| objtype | samiskforvaltningsomrade | lokalid | navnerom | versjonid | datafangstdato | oppdateringsdato | datauttaksdato | opphav | fylkesnummer | navn | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Fylke | false | 3a65f9e4-23d5-4c05-b188-8f4ea8463f8b | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20190301000000 | 20211209122812 | None | 42 | [ { "navn": "Agder", "objtype": "Administrativ... | POLYGON ((12650.920 6523939.770, 12654.850 652... | |
| 1 | Fylke | false | 6fa6cac4-9f86-4cbf-9ae4-716eb5059541 | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122812 | None | 03 | [ { "navn": "Oslo", "objtype": "AdministrativE... | POLYGON ((255493.650 6656227.710, 255593.360 6... | |
| 2 | Fylke | JA | 545cbfe3-2f34-4792-a9e9-135375accefd | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122812 | None | 54 | [ { "navn": "Troms og Finnmark", "objtype": "A... | POLYGON ((701859.740 7853460.760, 680484.030 7... | |
| 3 | Fylke | false | ab9f3402-23fb-48b4-a4fd-dbe4e3cc321b | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122812 | None | 15 | [ { "navn": "Møre og Romsdal", "objtype": "Adm... | POLYGON ((-20575.890 6963321.310, -25091.800 6... | |
| 4 | Fylke | false | 22642144-2de8-4e9d-bea0-0520fb44e85a | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20190913000000 | 20211209122812 | None | 38 | [ { "navn": "Vestfold og Telemark", "objtype":... | POLYGON ((78548.430 6606728.760, 78556.900 660... | |
| 5 | Fylke | JA | ea3b82cf-f063-41a9-a19c-449832aadf3a | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122812 | None | 50 | [ { "navn": "Trøndelag", "objtype": "Administr... | POLYGON ((228157.810 7170172.040, 207751.950 7... | |
| 6 | Fylke | false | e70c69ba-5bea-48a8-952c-b4860ada5afa | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122812 | None | 11 | [ { "navn": "Rogaland", "objtype": "Administra... | POLYGON ((-92079.540 6636303.790, -96094.590 6... | |
| 7 | Fylke | false | f96e22cd-cd45-48a3-99b8-a3d5b78c76b4 | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20190225000000 | 20211209122812 | None | 34 | [ { "navn": "Innlandet", "objtype": "Administr... | POLYGON ((125061.480 6809053.300, 125036.470 6... | |
| 8 | Fylke | false | f2e85556-471b-4807-a1bf-6da7478e7cda | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20190225000000 | 20211209122812 | None | 30 | [ { "navn": "Viken", "objtype": "Administrativ... | POLYGON ((162857.290 6678845.090, 163199.630 6... | |
| 9 | Fylke | JA | ee7fa255-8172-47f2-8f83-6076ccf1bb4f | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20211115000000 | 20211209122812 | None | 18 | [ { "navn": "Nordland", "objtype": "Administra... | POLYGON ((372929.380 7521632.830, 360585.200 7... | |
| 10 | Fylke | false | 173150173151 | http://skjema.geonorge.no/SOSI/produktspesifik... | 4.1 | 20200207000000 | 20211209122813 | None | 46 | [ { "navn": "Vestland", "objtype": "Administra... | POLYGON ((-86165.900 6792746.680, -84865.720 6... |
Each GeoSeries has its Coordinate Reference System (CRS) accessible at GeoSeries.crs. The CRS tells GeoPandas where the coordinates of the geometries are located on the earth’s surface. In some cases, the CRS is geographic, which means that the coordinates are in latitude and longitude. In those cases, its CRS is WGS84, with the authority code EPSG:4326. Let’s see the projection of our Norway GeoDataFrame.
norge.crs
<Derived Projected CRS: EPSG:25833> Name: ETRS89 / UTM zone 33N Axis Info [cartesian]: - E[east]: Easting (metre) - N[north]: Northing (metre) Area of Use: - name: Europe between 12°E and 18°E: Austria; Denmark - offshore and offshore; Germany - onshore and offshore; Norway including Svalbard - onshore and offshore. - bounds: (12.0, 46.4, 18.0, 84.42) Coordinate Operation: - name: UTM zone 33N - method: Transverse Mercator Datum: European Terrestrial Reference System 1989 ensemble - Ellipsoid: GRS 1980 - Prime Meridian: Greenwich
norge.area
0 2.305731e+10 1 4.810366e+08 2 1.161332e+11 3 2.554877e+10 4 2.024325e+10 5 5.968706e+10 6 1.663051e+10 7 5.211183e+10 8 2.584184e+10 9 8.050724e+10 10 4.986524e+10 dtype: float64
norge.boundary
0 LINESTRING (12650.920 6523939.770, 12654.850 6... 1 LINESTRING (255493.650 6656227.710, 255593.360... 2 LINESTRING (701859.740 7853460.760, 680484.030... 3 LINESTRING (-20575.890 6963321.310, -25091.800... 4 LINESTRING (78548.430 6606728.760, 78556.900 6... 5 LINESTRING (228157.810 7170172.040, 207751.950... 6 LINESTRING (-92079.540 6636303.790, -96094.590... 7 LINESTRING (125061.480 6809053.300, 125036.470... 8 MULTILINESTRING ((162857.290 6678845.090, 1631... 9 LINESTRING (372929.380 7521632.830, 360585.200... 10 LINESTRING (-86165.900 6792746.680, -84865.720... dtype: geometry
norge.centroid
0 POINT (76085.466 6511179.375) 1 POINT (262250.904 6656330.653) 2 POINT (821585.665 7786813.996) 3 POINT (101811.400 6977403.140) 4 POINT (154922.651 6602359.966) 5 POINT (298890.055 7093647.954) 6 POINT (-23047.568 6579824.752) 7 POINT (256976.692 6820201.705) 8 POINT (220137.581 6666944.356) 9 POINT (452632.751 7445560.745) 10 POINT (11295.203 6786847.403) dtype: geometry
Measure distance between points:
point = norge.centroid.iloc[0]
norge.distance = norge.centroid.distance(point)
norge.distance
0 0.000000e+00 1 2.360645e+05 2 1.477503e+06 3 4.669330e+05 4 1.205371e+05 5 6.236277e+05 6 1.205800e+05 7 3.580732e+05 8 2.121644e+05 9 1.007401e+06 10 2.831795e+05 dtype: float64
Note that geopandas.GeoDataFrame is a subclass of pandas.DataFrame, so we have all the pandas functionality available to use on the geospatial dataset — we can even perform data manipulations with the attributes and geometry information together.
For example, to calculate the average of the distances measured above, access the distance column and call the mean() method on it:
norge.distance.mean()
446005.7367762395
GeoPandas can also plot maps, so we can check how the geometries appear in space. To plot the active geometry, call GeoDataFrame.plot(). To color code by another column, pass in that column as the first argument. In the example below, we plot the active geometry column and color code by the "area" column. We also want to show a legend (legend=True).
norge.plot('fylkesnummer', legend=True, figsize=(10,10))
<AxesSubplot:>
norge.explore('fylkesnummer', legend=True)
Let's plot E6 traffic registration stations on the map of Norway
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(15,9))
ax.set_aspect('equal')
norge.plot('fylkesnummer', ax=ax)
gdf.plot(ax=ax, color='black')
<AxesSubplot:>
A lot of interesting open data is available from Statens Vegvesen via Vegkart: https://vegkart.atlas.vegvesen.no/
All available data is listed in the Datakatalog: https://datakatalogen.vegdata.no/
We now learn how to import this data into Geopandas. There is a Python library available to extract data from Vegkart: https://github.com/LtGlahn/nvdbapi-V3. However, version 3 of this package does not include the functionality to convert the data to GeoJSON format. I've extracted that code from version 2 of nvdbapi and imported it into my own fork of version 3: https://github.com/alexdiem/nvdbapi-V3. We will use this code to import Vegkart data into GeoPandas.
import nvdbapiv3 as nvdb
from nvdbapiv3 import nvdb2geojson
The data saved in Vegkart is encoded into numerical IDs according to Datakatalog:
q = nvdb.nvdbFagdata(482) # Trafikkregistreringsstasjoner
# (Status=Operativ OR Status=Midlertidig ute av drift) AND Trafikantgruppe=Sykkel
q.filter({"egenskap": "(5201=7081 OR 5201=12987) AND 9293=12993"})
q_geo = nvdb2geojson.fagdata2geojson(q)
qdf = gpd.GeoDataFrame.from_features(q_geo['features'])
qdf.set_crs(epsg=25833)
| geometry | Geometri, punkt | Regulering gangfelt (Ny) | Regulering vegkryss (Ny) | UID (Ny) | Ukedagstype (Ny) | Ulykkestype (Ny) | Ulykkestype underkategori (Ny) | År (Ny) | Antall Andre enheter (Ny) | ... | kommune | fylke | Temperatur | Historisk Kryssdel (Ny) | Historisk Kryssdel meterverdi (Ny) | kryssystem | sluttdato | Historisk Sideanleggsdel (Ny) | Historisk Sideanleggsdel meterverdi (Ny) | sideanlegg | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | POINT Z (544533.382 7568315.821 4.924) | POINT (544528 7568318) | Ikke gangfelt | Ukjent | UID0257461683 | Helgedøgn | Fotgjenger/akende | Fotgjenger krysset kjørebanen | 2020 | 0 | ... | 1875 | 18 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 1 | POINT Z (1014115.062 7843588.599 4.654) | POINT (1014110 7843577) | Ikke gangfelt | Ikke i vegkryss | UID1287984162 | Yrkesdøgn | Utforkjøring | Enslig kjøretøy kjørte utfor vegen | 2020 | 0 | ... | 5442 | 54 | 6.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 2 | POINT Z (540007.924 7498047.595 13.952) | POINT (540015 7498073) | Ikke gangfelt | Ikke i vegkryss | UID8346400236 | Yrkesdøgn | Motsatt kjøreretning | Ulykke ved møting | 2020 | 0 | ... | 1845 | 18 | 17.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3 | POINT Z (95855.987 6930249.666 14.410) | POINT (95856 6930251) | Ikke gangfelt | Ikke i vegkryss | UID1936715838 | Helgedøgn | Motsatt kjøreretning | Ulykke ved møting | 2020 | 0 | ... | 1578 | 15 | 17.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 4 | POINT Z (-33337.425 6569927.324 49.668) | POINT (-33324 6569920) | Ikke gangfelt | Ukjent | UID2557581828 | Yrkesdøgn | Samme kjøreretning | Ulykke mellom kjøretøy med samme kjøreretning | 2020 | 0 | ... | 1103 | 11 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3536 | POINT Z (274731.099 7040232.000 103.167) | POINT (274732 7040227) | Gangfelt i kryss | Uregulert kryss, generell høyreregel (uten ski... | UID6677519512 | Helgedøgn | Fotgjenger/akende | Fotgjenger krysset kjørebanen | 2020 | 0 | ... | 5001 | 50 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3537 | POINT Z (261790.947 7027311.614 128.693) | POINT (261788 7027314) | Ikke gangfelt | Ikke i vegkryss | UID0058200042 | Helgedøgn | Utforkjøring | Enslig kjøretøy kjørte utfor vegen | 2020 | 0 | ... | 5028 | 50 | 10.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3538 | POINT Z (259233.075 6614798.935 81.879) | POINT (259236 6614800) | Ikke gangfelt | Vikepliktsregulert kryss (skilt 202, 204, 210) | UID6849910007 | Yrkesdøgn | Kryssende kjørereretning | Ulykke ved kryssende kjøreretning hvor kjøretø... | 2020 | 0 | ... | 3019 | 30 | 13.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3539 | POINT Z (537183.615 7506739.507 140.916) | POINT (537184 7506737) | Ikke gangfelt | Ukjent | UID2579406278 | Yrkesdøgn | Samme kjøreretning | Ulykke mellom kjøretøy med samme kjøreretning | 2020 | 0 | ... | 1845 | 18 | 6.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 3540 | POINT Z (365817.819 7239876.120 4.487) | POINT (365820 7239877) | Ikke gangfelt | Ikke i vegkryss | UID2323791110 | Yrkesdøgn | Utforkjøring | Enslig kjøretøy kjørte utfor vegen | 2020 | 0 | ... | 1812 | 18 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3541 rows × 84 columns